﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XML_Indexing;
using CDE_Model;

namespace XPath_2
{
    enum XPathMode
    {
        FindChild,
        FindChildren
    }

    public class XPathEvaluator
    {
        #region Fields

        private IXMLIndex _index;
        private String _path;
        private XPathMode _mode;

        #endregion

        #region Properties

        public IXMLIndex Index
        {
            get { return _index; }
        }

        public String Path
        {
            get { return _path; }
        }

        private XPathMode Mode
        {
            get { return _mode; }
        }

        #endregion

        #region Constructors

        public XPathEvaluator(IXMLIndex index, String path)
        {
            _index = index;
            _path = path;
            _mode = XPathMode.FindChildren;
        }

        #endregion

        #region Methods

        public List<Element> Evaluate()
        {
            if (Mode.Equals(XPathMode.FindChildren))
            {
                if (Path.ToCharArray()[0] == '/')
                {
                    _path = Path.Substring(1);
                }

                String[] identifierList = Path.Split('/');

                if (Index.Node.GenericIdentifier.Equals(identifierList[0]))
                {
                    String newPath = String.Empty;

                    for (int i = 1; i < identifierList.Length; i++)
                    {
                        if (i != identifierList.Length - 1)
                        {
                            newPath += identifierList[i] + "/";
                        }
                        else
                        {
                            newPath += identifierList[i];
                        }
                    }

                    List<IXMLIndex> indexList = new List<IXMLIndex>();
                    indexList.Add(Index);
                    return Evaluate(indexList, newPath);
                }
            }

            return null;
        }

        private List<Element> Evaluate(List<IXMLIndex> nodeIndexes, String path)
        {
            List<Element> listOfElements = new List<Element>();

            foreach (IXMLIndex currentNode in nodeIndexes)
            {
                if (Mode.Equals(XPathMode.FindChildren))
                {
                    String[] identifierList = path.Split('/');

                    if (identifierList.Length > 1)
                    {
                        String newPath;
                        List<IXMLIndex> indexes;
                        BuildNewPath(currentNode, identifierList, out newPath, out indexes);

                        return Evaluate(indexes, newPath);
                    }
                    else
                    {
                        if (currentNode.FindChildren(identifierList[0]) != null)
                        {
                            foreach(IXMLIndex i in currentNode.FindChildren(identifierList[0]))
                            {
                                listOfElements.Add(i.Node);
                            }
                        }
                    }
                }
            }

            return listOfElements;
        }

        private static void BuildNewPath(IXMLIndex currentNode, String[] identifierList, out String newPath, out List<IXMLIndex> indexes)
        {
            newPath = String.Empty;

            for (int i = 1; i < identifierList.Length; i++)
            {
                if (i != identifierList.Length - 1)
                {
                    newPath += identifierList[i] + "/";
                }
                else
                {
                    newPath += identifierList[i];
                }
            }

            indexes = currentNode.FindChildren(identifierList[0]);
        }

        #endregion
    }
}
